package uform.model.core;

import uform.model.cell.ArrayCell;
import uform.model.cell.ValueCell;
import thx.validation.RangeValidator;
import thx.validation.StringLengthValidator;
import uform.model.value.BoolType;
import uform.model.value.FloatType;
import uform.model.value.StringType;
import utest.Assert;
import uform.model.core.Crawler;
import thx.util.Result;
//import uform.model.value.StringKind;

class TestSchema extends Test
{
	public function testResolve()
	{
		var schema = new Schema();
		schema.addCell("name", new ValueCell(new StringType()));
		var aschema = new Schema();
		aschema.addCell("street", new ValueCell(new StringType()));
		aschema.addCell("town", new ValueCell(new StringType()));
		schema.addCell("address", new ValueCell(aschema));
	
		var target : Dynamic = { };
		var crawler = new Crawler("name", target);
		
		schema.resolve(crawler);
		Assert.isNull(crawler.get());
		crawler.set("franco");
		Assert.equals("franco", crawler.get());
		
		
		var crawler = new Crawler("address.street", target);
		schema.resolve(crawler);
		Assert.isNull(crawler.get());
		crawler.set("main road");
		Assert.equals("main road", crawler.get());
		
		var crawler = new Crawler("address.town", target);
		schema.resolve(crawler);
		Assert.isNull(crawler.get());
		crawler.set("perfect city");
		Assert.equals("perfect city", crawler.get());
	}
	
	public function testParser()
	{
		var schema = new Schema();
		schema.addCell("name",  new ValueCell(new StringType()));
		schema.addCell("age",   new ValueCell(new FloatType()));
		schema.addCell("email", new ValueCell(new StringType()));
		
		var sub = new Schema();
		sub.addCell("street", new ValueCell(new StringType()));
		schema.addCell("addresses", new ArrayCell(sub));
		
		var target : Dynamic = schema.parse("{}");
		Assert.same( { }, target);
		
		target = schema.parse("{name:franco,email:franco.ponticelli@example.com,age:38,addresses:[{street:'my\n\"road\"'} , { street: other}]}");

		Assert.same({name:"franco",email:"franco.ponticelli@example.com",age:38.0,addresses:[{street:'my\n"road"'},{street:'other'}]}, target);
		
		assertValidation(schema.validate(target), true);
		
		var ser = schema.render(target);
		Assert.same(target, schema.parse(ser));
	}
	
	public function testInstance()
	{
		var schema = new Schema();
		Assert.isFalse(schema.fields().hasNext());
		schema.addCell("name", new ValueCell(new StringType()));
		Assert.isTrue(schema.fields().hasNext());
		Assert.notNull(schema.get("name"));
		schema.remove("name");
		Assert.isFalse(schema.fields().hasNext());
		Assert.isNull(schema.get("name"));
	}
	
	public function testValidateType()
	{
		var schema = new Schema();
		assertValidation(schema.validateType(null), false);
		assertValidation(schema.validateType(1), false);
//		assertValidation(schema.validateType("a"), false);
//		assertValidation(schema.validateType([]), false);
//		assertValidation(schema.validateType(new TestSchema()), false);
		assertValidation(schema.validateType(Result.Ok), false);
		assertValidation(schema.validateType({}), true);
	}
	
	public function testValidateEmptySchema()
	{
		var schema = new Schema(false, true);
		assertValidation(schema.validate( { } ), true);
		assertValidation(schema.validate( { name : "franco" } ), false);
		
		var schema = new Schema(true, true);
		assertValidation(schema.validate( { } ), true);
		assertValidation(schema.validate( { name : "franco" } ), true);
	}
	
	public function testValidate()
	{
		var schema = new Schema(false, false);
		schema.addCell("name", new ValueCell(new StringType(), true));
		assertValidation(schema.validate( { } ), true);
		schema.emptyFieldsShouldBeDeclared = true;
		assertValidation(schema.validate( { } ), false);
		assertValidation(schema.validate( { name : "franco" } ), true);
		assertValidation(schema.validate( { name : 1 } ), false);
	}
	
	public function testComplex()
	{
		var schema = new Schema()
			.addCell("name",   new ValueCell(new StringType().addValidator(new StringLengthValidator(2, 100))))
			.addCell("emails", new ArrayCell(new StringType().addValidator(new StringLengthValidator(3))))
			.addCell("age",    new ValueCell(new FloatType ().addValidator(new RangeValidator(13, 150))))
			.addCell("male",   new ValueCell(new BoolType  ()))
			.addCell("score",  new ValueCell(new FloatType ().addValidator(new RangeValidator(0.0, 10.0)), true))
			;
		assertValidation(schema.validate( { name : "franco" } ), false);
		
		assertValidation(schema.validate( {
			name : "franco",
			age  : 38,
			male : true
		} ), true);
		
		assertValidation(schema.validate( {
			name   : "franco",
			emails : ["franco.ponticelli@gmail.com"],
			age    : 38,
			male   : true,
			score  : 9.0
		} ), true);
		
		assertValidation(schema.validate( {
			name   : "f",
			emails : ["franco.ponticelli@gmail.com"],
			age    : 38,
			male   : true,
			score  : 9.0
		} ), false);
		
		var schema = new Schema()
			.addCell("names", new ArrayCell(new StringType(), 2, 4))
			;
		
		assertValidation(schema.validate( {
			names : null
		} ), false);
		
		assertValidation(schema.validate( {
			names : [1, 2]
		} ), false);
		
		assertValidation(schema.validate( {
			names : ["1", "2"]
		} ), true);
		
		assertValidation(schema.validate( {
			names : ["1", "2", "3", "4", "5"]
		} ), false);
	}
	
	public function new();
}